// 请求地址
const baseUrl = 'http://localhost:8000'
// 白名单
const whiteList = ['/auth/oauth2/token', '/auth/login', '/admin-api/system/file/upload/public']

/**
 * 请求拦截器
 */
const httpInterceptor = {
  /**
   * 拦截前触发
   * @param options UniApp.RequestOptions
   */
  invoke(options: UniApp.RequestOptions) {
    // 设置请求超时
    options.timeout = 30000
    // 设置请求头
    options.header = {
      ...options.header,
    }
    // 白名单请求不设置token
    if (!whiteList.includes(options.url)) {
      // 设置token
      options.header.Authorization = `Bearer ${useUserStoreHook().accessToken}`
    }
    console.log(options.url)

    if (options.url === '/auth/oauth2/token') {
      options.header.Authorization = `Basic ${getAuthorization()}`
      options.header['Content-Type'] = 'application/x-www-form-urlencoded'
    }

    // TODO 小程序没有请求URL如何区分多租户？？
    const tenantId = useUserStoreHook().getTenantId()
    if (tenantId) {
      options.header['x-tenant-id'] = tenantId
    }
    // #ifdef MP-WEIXIN
    if (!tenantId) {
      options.header['x-tenant-id'] = 0
    }
    // #endif
    // 非http开头拼接Url
    if (!options.url.startsWith('http')) {
      options.url = baseUrl + options.url
    }
  },
}

function getAuthorization() {
  const clientId = import.meta.env.VITE_AUTH_CLIENT_ID
  const clientSecret = import.meta.env.VITE_AUTH_CLIENT_SECRET
  return uni.arrayBufferToBase64(stringToArrayBuffer(`${clientId}:${clientSecret}`))
}

function stringToArrayBuffer(str: string) {
  const buf = new ArrayBuffer(str.length)
  const view = new Uint8Array(buf)
  for (let i = 0; i < str.length; i++) {
    view[i] = str.charCodeAt(i)
  }
  return buf
}

// 配置拦截器
uni.addInterceptor('request', httpInterceptor)
uni.addInterceptor('uploadFile', httpInterceptor)

// 请求方法
type RequestMethods = 'GET' | 'POST' | 'PUT' | 'DELETE'

interface RequestOptions {
  method: RequestMethods
  url: string
  data?: any
  options?: UniApp.RequestOptions
}

class Http {
  /** token过期后，暂存待执行的请求 */
  private requests: Array<() => Promise<ResultData<any>>> = []
  /** 防止重复刷新token */
  private isRefreshing = false

  /**
   * 请求封装
   * @param method 请求方法
   * @param url 请求地址
   * @param data 请求参数
   * @param options 配置
   */
  public request = <T>(
    method: RequestMethods,
    url: string,
    data?: any,
    options?: UniApp.RequestOptions,
  ) => {
    return new Promise<ResultData<T>>((resolve, reject) => {
      uni.request({
        url,
        method,
        data,
        ...options,
        success: (res) => {
          this.ResponseInterceptor<T>(res, {
            method,
            url,
            data,
            options,
          })
            .then((res: ResultData<T>) => {
              resolve(res)
            })
            .catch((res) => {
              reject(res)
            })
        },
        fail: (err) => {
          uni.showToast({
            title: '网络错误，换个网络试试',
            icon: 'none',
          })
          reject(err)
        },
      })
    })
  }

  /**
   * 响应拦截器
   * @param res 响应参数
   * @param options 请求参数
   * @private
   */
  private ResponseInterceptor<T>(
    res: UniApp.RequestSuccessCallbackResult,
    options: RequestOptions,
  ) {
    return new Promise<ResultData<T>>((resolve, reject) => {
      const result = res.data as ResultData<T>
      if (result.code >= 200 && result.code < 300) {
        resolve(result)
      }
      else if (result.code === 401) {
        this.requests.push(() => {
          return this.request(options.method, options.url, options.data, options.options)
        })
        this.RefreshToken()
      }
      else {
        // 其它报错-> 轻提示
        uni.showToast({
          title: result.msg || '请求错误',
          icon: 'none',
        })
        reject(result.msg)
        throw new Error(result.msg || '请求错误')
      }
    })
  }

  /**
   * 刷新token
   * @private
   */
  private RefreshToken() {
    // 防止重复刷新
    if (this.isRefreshing) {
      return
    }
    // 未登录
    if (useUserStoreHook().refreshToken == null) {
      useUserStoreHook().logout()
      return
    }
    this.isRefreshing = true
    // // 刷新token
    // useUserStoreHook()
    //   .handRefreshToken()
    //   .then(() => {
    //     // 执行请求
    //     this.requests.forEach((request) => {
    //       request()
    //     })
    //     this.requests = []
    //   })
    //   .catch(() => {
    //     useUserStoreHook().logout()
    //   })
    //   .finally(() => {
    //     this.isRefreshing = false
    //   })
  }
}

export const http = new Http()
